package graphics.datastructures;

import graphics.raytracing.Ray;
import graphics.raytracing.Tracable;

import java.io.Serializable;

import static java.lang.Math.*;
import static util.MatrixOperationsF.*;

public class BoundingBox<T extends Tracable> implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = -98597576331122964L;
	private float[] _rtf;
	private float[] _bln;
	private final int x=0;
	private final int y=1;
	private final int z=2;
	/**
	 * 
	 * @param bln{minx,miny,minz}
	 * @param rtf{maxx,maxy,maxz}
	 */
	public BoundingBox(float[] bln,float[] rtf)
	{
		_bln = bln;
		_rtf = rtf;
	}
	public BoundingBox(BoundingBox<T> right) {
		this(ar(right.bln()),ar(right.rtf()));
	}
	public BoundingBox(float[][] bb) {
		this(bb[0],bb[1]);
	}
	public boolean intersects(Ray ray)
	{
		float[]TnearTfar = new float[2];
		TnearTfar[0]=-Float.MAX_VALUE;
		TnearTfar[1]=Float.MAX_VALUE;
		test(x,ray,TnearTfar);
		if(TnearTfar[0]>TnearTfar[1])
			return false;
		test(y,ray,TnearTfar);
		if(TnearTfar[0]>TnearTfar[1])
			return false;
		test(z,ray,TnearTfar);
		if(TnearTfar[0]>TnearTfar[1])
			return false;
		return true;
	}
	private void test(int x, Ray ray, float[] tntf) {
		float[] o =ray.getOrigin();
		float[] d =ray.getDirection();
		float t1 =(_bln[x]-o[x])/d[x];
		float t2 =(_rtf[x]-o[x])/d[x];
		if(t1>t2)
		{
			float t = t2;
			t2=t1;
			t1=t;
		}
		tntf[0]=Math.max(tntf[0], t1);
		tntf[1]=Math.min(tntf[1], t2);
	}
	public boolean testInclusion(float[]point)
	{
		boolean bX = point[x]<=_rtf[x]&&point[x]>=_bln[x];
		boolean bY = point[y]<=_rtf[y]&&point[y]>=_bln[y];
		boolean bZ = point[z]<=_rtf[z]&&point[z]>=_bln[z];
		return bX&&bY&&bZ;
	}
	public static <T extends Tracable> BoundingBox<T> union(BoundingBox<T> l, BoundingBox<T> r) {
		float[] lbn = new float[3];
		float[] rtf= new float[3];
		for(int i = 0 ; i < lbn.length;i++)
		{
			lbn[i] = min(l._bln[i],r._bln[i]);
			rtf[i] =max(l._rtf[i],r._rtf[i]);
		}
		return new BoundingBox<T>(lbn,rtf);
	}
	public float[] bln() {
		return _bln;
	}
	public float[] rtf()
	{
		return _rtf;
	}
}
